package com.cdy.demo.agent;

import javassist.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.cdy.demo.agent.Agent.commandLineContext;


public class WatchCommand implements Command{

    public static final String startString = "{" +
            "start.set(System.currentTimeMillis()+\"\");" +
            "}";
    public static final String endString = "{" +
            "long time = System.currentTimeMillis() - Long.parseLong(start.get().toString());" +
            "System.out.print(Thread.currentThread().getStackTrace()[2] + \"方法耗费时间: \");" +
            "System.out.println(time + \"毫秒\");" +
            "}";


    @Override
    public boolean meet() {
        return commandLineContext.getCommandType().equals("watch") ||
                commandLineContext.getCommandType().equals("all");
    }

    public byte[] transform(CommandContext context)  {
        String className = context.getClassName();
        String clazz = commandLineContext.getCommandClass();
        String methodName = commandLineContext.getCommandMethod();
        if (className.equals(clazz)) {
            CtClass ctclass = null;
            try {
                ClassPool classPool = ClassPool.getDefault();
//                createTimeStat();
                ctclass = classPool.get(className);// 使用全称,用于取得字节码类<使用javassist>
                CtMethod ctMethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
                System.out.println(ctMethod.getName());

//                        ctMethod.addLocalVariable("begin", CtClass.longType);
//                        ctMethod.addLocalVariable("end", CtClass.longType);
//                        ctMethod.insertBefore("begin = System.currentTimeMillis();");
//                        ctMethod.insertAfter("System.out.println(\"方法" + ctMethod.getName() + "耗时\"+ (end - begin) +\"ms\");");

                ctMethod.insertBefore("com.cdy.demo.agent.TimeStat.start();");
                ctMethod.insertAfter("com.cdy.demo.agent.TimeStat.end();");
                byte[] byteArr = ctclass.toBytecode();
                File file = new File("/Users/chendongyi/Downloads/ideaProjects/demo_maven/target/Emp.class");
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(byteArr);
                fos.close();
                return byteArr;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return context.getClassfileBuffer();
    }

//    public static void createTimeStat() throws IOException, NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//        ClassPool classPool = ClassPool.getDefault();
//        CtClass ctClass = classPool.get("com.cdy.demo.agent.TimeStat");
//        if (ctClass != null) {
//            return;
//        }
//        classPool.makeClass("com.cdy.demo.agent.TimeStat");
//        ctClass = classPool.get("com.cdy.demo.agent.TimeStat");
//        CtField start = new CtField(classPool.getCtClass("java.lang.ThreadLocal"),"start",ctClass);
//        start.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
//        ctClass.addField(start,CtField.Initializer.byNew(classPool.getCtClass("java.lang.ThreadLocal")));
//
//        //添加构造函数
//        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
//        //为构造函数设置函数体
//        ctConstructor.setBody("{}");
//        ctClass.addConstructor(ctConstructor);
//
//        CtMethod ctMethod = new CtMethod(CtClass.voidType,"start",new CtClass[]{},ctClass);
//        ctMethod.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
//        ctMethod.setBody(startString);
//        ctClass.addMethod(ctMethod);
//
//        CtMethod ctMethod2 = new CtMethod(CtClass.voidType,"end",new CtClass[]{},ctClass);
//        ctMethod2.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
//        ctMethod2.setBody(endString);
//        ctClass.addMethod(ctMethod2);
//
//        Class<?> aClass = ctClass.toClass();
//        Object obj = aClass.newInstance();
//        for (Method declaredMethod : aClass.getDeclaredMethods()) {
//            System.out.println(declaredMethod.getName());
//            declaredMethod.invoke(null);
//        }
//    }

}
